package com.wzcl.app.controller;


import com.wzcl.app.dao.model.*;
import com.wzcl.app.dao.model.common.Promotion;
import com.wzcl.app.model.common.*;
import com.wzcl.app.model.dto.*;
import com.wzcl.app.model.vo.ActivityRuleVo;
import com.wzcl.app.model.vo.ActivityVo;
import com.wzcl.app.model.vo.OrderVo;
import com.wzcl.app.model.vo.PromotionVo;
import com.wzcl.app.service.*;
import com.wzcl.app.utils.LockUtil;
import com.wzcl.app.utils.RedisUtil;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.log4j.Log4j2;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import javax.validation.Valid;
import java.util.HashMap;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

@Log4j2
@RestController
@RequestMapping("/activity")
@Api(value="活动controller",tags={"活动管理接口"})
public class ActivityController {
    public static final String SECKILL_URL_KEY = "SECKILL_URL_";
    public static final String SECKILL_STOCK_KEY = "SECKILL_STOCK_";
    private static final String SECKILL_KEY = "SECKILL_";
    private static final String GROUP_KEY = "GROUP_";

    @Autowired
    private ActivityService activityService;

    @Autowired
    private ActivityRuleService ruleService;

    @Autowired
    private RedisUtil redisUtil;

    @Autowired
    private OrderService orderService;

    @Autowired
    private UserService userService;

    @Autowired
    private ActivityGroupService activityGroupService;

    @ApiOperation("创建一个新活动")
    @PostMapping("/add")
    public RVO<ActivityVo> addActivity(@RequestBody @Valid ActivityDto activityDto) {
        Activity activity = activityService.addActivity(activityDto);
        return RVO.success(ActivityVo.create(activity));
    }

    @ApiOperation("创建活动优惠")
    @PostMapping("/addDiscount")
    public RVO<String> addDiscount(@RequestBody @Valid PromotionDto promotionDto) {
        activityService.getFactoryByType(promotionDto.getType()).addPromotion(promotionDto);
        return RVO.success();
    }


    @ApiOperation("创建一个优惠的规则")
    @PostMapping("/addRule")
    public RVO<ActivityRuleVo> addActivityRule(@RequestBody @Valid ActivityRuleDto activityRuleDto) {
        ActivityRule rule = ruleService.addActivityRule(activityRuleDto);
        return RVO.success(ActivityRuleVo.create(rule));
    }

    @ApiOperation("删除一个活动")
    @PostMapping("/del")
    public RVO<ActivityVo> delActivity(@RequestBody ActivityDto activityDto) {
        Activity activity = activityService.delActivityById(activityDto.getId());
        return RVO.success(ActivityVo.create(activity));
    }

    @ApiOperation("删除一个优惠")
    @PostMapping("/delDiscount")
    public RVO<String> delDiscount(@RequestBody PromotionDto promotionDto) {
        activityService.getFactoryByType(promotionDto.getType()).deletePromotion(promotionDto.getId());
        return RVO.success();
    }

    @ApiOperation("删除一个活动的规则")
    @PostMapping("/delRule")
    public RVO<ActivityRuleVo> delActivityRule(@RequestBody ActivityRuleDto activityRuleDto) {
        ActivityRule rule = ruleService.delActivityRuleById(activityRuleDto.getId());
        return RVO.success(ActivityRuleVo.create(rule));
    }

    @ApiOperation("修改活动")
    @PostMapping("/update")
    public RVO<ActivityVo> updateActivity(@RequestBody @Valid ActivityDto activityDto) {
        Activity activity = activityService.updateActivity(activityDto);
        return RVO.success(ActivityVo.create(activity));
    }

    @ApiOperation("修改活动优惠")
    @PostMapping("/updateDiscount")
    public RVO<String> updateDiscount(@RequestBody @Valid PromotionDto promotionDto) {
        activityService.getFactoryByType(promotionDto.getType()).updatePromotion(promotionDto);
        return RVO.success();
    }

    @ApiOperation("修改活动规则")
    @PostMapping("/updateRule")
    public RVO<ActivityRuleVo> updateActivityRule(@RequestBody @Valid ActivityRuleDto activityRuleDto) {
        ActivityRule rule = ruleService.updateActivityRule(activityRuleDto);
        return RVO.success(ActivityRuleVo.create(rule));
    }

    @ApiOperation("查找一个活动")
    @PostMapping("/get")
    public RVO<ActivityVo> getActivity(@RequestBody ActivityDto activityDto) {
        Activity activity = activityService.getActivityById(activityDto.getId());
        if (activity != null) {
            return RVO.success(ActivityVo.create(activity));
        }
        return RVO.success(null);
    }

    @ApiOperation("查找一个活动优惠")
    @PostMapping("/getDiscount")
    public RVO<PromotionVo> getDiscount(@RequestBody PromotionDto promotionDto) {
        Promotion promotion = activityService.getFactoryByType(promotionDto.getType()).getPromotionById(promotionDto.getId());
        if (promotion != null) {
            return RVO.success(PromotionVo.create(promotion));
        }
        return RVO.success(null);
    }

    @ApiOperation("查找一个活动的规则")
    @PostMapping("/getRule")
    public RVO<ActivityRuleVo> getActivityRule(@RequestBody ActivityRuleDto activityRuleDto) {
        ActivityRule rule = ruleService.getActivityRuleById(activityRuleDto.getId());
        if (rule != null) {
            return RVO.success(ActivityRuleVo.create(rule));
        }
        return RVO.success(null);
    }

    @ApiOperation("查找活动")
    @PostMapping("/getList")
    public RVO<List<ActivityVo>> findActivityList(@RequestBody ActivityDto activityDto) {
        List<Activity> list = activityService.getActivityList(activityDto);
        if (list != null && list.size() > 0) {
            List<ActivityVo> collect = list.stream().map(ActivityVo::create).collect(Collectors.toList());
            return RVO.success(collect);
        }
        return RVO.success(null);
    }

    @ApiOperation("查找活动优惠")
    @PostMapping("/getDiscountList")
    public RVO<List<PromotionVo>> findDiscountList(@RequestBody PromotionDto promotionDto) {
        Activity activity = activityService.getAndCheckById(promotionDto.getActivityId());
        List<Promotion> list = activityService.getFactoryByType(activity.getType()).findAllPromotion(activity.getId());
        if (list != null && list.size() > 0) {
            return RVO.success(list.stream().map(PromotionVo::create).collect(Collectors.toList()));
        }
        return RVO.success(null);
    }

    @ApiOperation("查找活动规则")
    @PostMapping("/getRuleList")
    public RVO<List<ActivityRuleVo>> findActivityRuleList(@RequestBody ActivityRuleDto activityRuleDto) {
        List<ActivityRule> ruleList = ruleService.getActivityRuleList(activityRuleDto);
        if (ruleList != null && ruleList.size() > 0) {
            RVO.success(ruleList.stream().map(ActivityRuleVo::create).collect(Collectors.toList()));
        }
        return RVO.success(null);
    }

    @ApiOperation("分页查找活动")
    @PostMapping("/getPage")
    public RVO<List<ActivityVo>> findActivityPage(@RequestBody ActivityDto activityDto) {
        MyPage<Activity> page = activityService.getActivityPage(activityDto);
        if (page != null && page.getContent().size() > 0) {
            List<ActivityVo> collect = page.getContent().stream().map(ActivityVo::create).collect(Collectors.toList());
            return RVO.success(collect, page);
        }
        return RVO.success(null);
    }

    @ApiOperation("分页查找优惠")
    @PostMapping("/getDiscountPage")
    public RVO<List<PromotionVo>> findDiscountByPage(@RequestBody PromotionDto promotionDto) {
        MyPage<Promotion> page = activityService.getFactoryByType(promotionDto.getType()).findPromotionPage(promotionDto);
        if (page != null && page.getContent().size() > 0) {
            return RVO.success(page.getContent().stream().map(PromotionVo::create).collect(Collectors.toList()));
        }
        return RVO.success(null);
    }

    @ApiOperation("分页查找一个活动优惠的规则")
    @PostMapping("/getRulePage")
    public RVO<List<ActivityRuleVo>> findRuleByPage(@RequestBody ActivityRuleDto activityRuleDto) {
        MyPage<ActivityRule> page = ruleService.getActivityRulePage(activityRuleDto);
        if (page != null && page.getContent().size() > 0) {
            return RVO.success(page.getContent().stream().map(ActivityRuleVo::create).collect(Collectors.toList()), page);
        }
        return RVO.success(null);
    }

    @ApiOperation("发布/预发布/取消活动")
    @PostMapping("/publish")
    public RVO<String> publishActivity(@RequestBody ActivityDto activityDto) {
        activityService.publishActivity(activityDto);
        return RVO.success();
    }

    @ApiOperation("确认资格")
    @PostMapping("/check")
    public RVO<Boolean> check(@RequestBody ActivityDto activityDto) {
        String phone = SecurityContextHolder.getContext().getAuthentication().getName();
        AppUser user = userService.getUserByPhone(phone);
        return RVO.success(activityService.checkActivity(user, activityService.getAndCheckById(activityDto.getId()), new HashMap<>()));
    }

    @ApiOperation("获取秒杀地址")
    @PostMapping("/seckillUrl/{commodityId}")
    public RVO<String> seckillUrl(@PathVariable Integer commodityId, @RequestBody ActivityDto activityDto) {
        if (activityDto.getId() == null) {
            throw new BusinessException(CodeMsg.MUST_BE_NOT_NULL, "无活动ID");
        }
        String key = SECKILL_URL_KEY + commodityId + "_" + activityDto.getId();
        if (!redisUtil.hasKey(key)) {
            redisUtil.set(key, "无秒杀活动信息", 60);
            throw new BusinessException(CodeMsg.ACTIVITY_NOT_EXIST, "无秒杀活动信息");
        }
        return RVO.success(String.valueOf(redisUtil.get(key)));
    }

    @ApiOperation("秒杀")
    @Transactional
    @PostMapping("/seckill")
    public RVO seckill(@RequestBody SpecificationsDto specificationsDto, HttpServletRequest request) {
        String commodityId = request.getParameter("cid");
        String activityId = request.getParameter("aid");
        String sign = request.getParameter("sign");
        if (activityService.checkSign(commodityId, activityId, sign)) {
            try {
                LockUtil.lock(SECKILL_KEY + commodityId + "_" + activityId, TimeUnit.SECONDS, 5 * 60);
                Object obj = redisUtil.get(SECKILL_STOCK_KEY + commodityId + "_" + activityId);
                if (obj == null) {
                    throw new BusinessException(CodeMsg.COMMODITY_COUNT_SHOP, "秒杀活动已结束");
                }
                int stock = Integer.parseInt(String.valueOf(obj));
                if (stock <= 0) {
                    //库存不足，结束活动
                    ActivityDto activityDto = new ActivityDto();
                    activityDto.setId(Integer.valueOf(activityId));
                    activityDto.setActivityState(WZCL.ACTIVITY_STATE.OFFLINE);
                    activityService.publishActivity(activityDto);
                    throw new BusinessException(CodeMsg.COMMODITY_COUNT_SHOP, "库存不足,秒杀活动结束");
                }
                String phone = SecurityContextHolder.getContext().getAuthentication().getName();
                AppUser user = userService.getAndCheckByPhone(phone);
                //校验并创建基础的订单
                Orders orders = orderService.seckillCheck(user, commodityId, activityId, specificationsDto.getSpec());
                //减库存
                redisUtil.set(SECKILL_STOCK_KEY + commodityId + "_" + activityId, --stock);
                return RVO.success(OrderVo.create(orders));
            } catch (BusinessException e) {
                throw e;
            } catch (Exception e) {
                log.error("秒杀接口调用失败:{} \r\n 堆栈信息:{}", e.getMessage(), BusinessException.collectExceptionStackMsg(e));
            } finally {
                LockUtil.unlock(SECKILL_KEY + commodityId + "_" + activityId);
            }
            return RVO.error("服务器异常,请重试！！！");
        }
        return RVO.error("验签失败,非法链接！！！");
    }

    @Transactional
    @ApiOperation("参加拼团活动")
    @PostMapping("/group/{promotionId}")
    public RVO group(@PathVariable Integer promotionId, @RequestBody ActivityGroupDto activityGroupDto) {
        Integer commodityId = activityGroupDto.getCommodityId();
        Integer activityId = activityGroupDto.getActivityId();
        if(commodityId == null){
            throw new BusinessException(CodeMsg.MUST_BE_NOT_NULL,"缺少商品Id");
        }
        try {
            LockUtil.lock(GROUP_KEY + commodityId + "_" + activityId, TimeUnit.SECONDS, 5 * 60);
            String phone = SecurityContextHolder.getContext().getAuthentication().getName();
            AppUser user = userService.getAndCheckByPhone(phone);
            Orders orders = orderService.groupCheck(user, commodityId, activityId,promotionId,activityGroupDto.getSpec(),activityGroupDto.getId());
            return RVO.success(OrderVo.create(orders));
        }catch (BusinessException e) {
            throw e;
        } catch (Exception e){
            log.error("拼团接口调用失败:{} \r\n 堆栈信息:{}", e.getMessage(), BusinessException.collectExceptionStackMsg(e));
        } finally {
            LockUtil.unlock(GROUP_KEY + commodityId + "_" + activityId);
        }
        return RVO.error("服务器异常,请重试！！！");
    }

    @ApiOperation("查看正在拼团的信息")
    @PostMapping("/getGroup")
    public RVO<ActivityGroup> getGroup(@RequestBody ActivityGroupDto activityGroupDto){
        return RVO.success(activityGroupService.getAndCheckById(activityGroupDto));
    }

    @ApiOperation("查看正在拼团的信息")
    @PostMapping("/getGroupList")
    public RVO<List<ActivityGroup>> getGroupList(@RequestBody ActivityGroupDto activityGroupDto){
        if(activityGroupDto.getActivityId() == null || activityGroupDto.getCommodityId() == null){
            throw new BusinessException(CodeMsg.MUST_BE_NOT_NULL,"请填写需要查询的活动ID和商品ID");
        }
        activityGroupDto.setGroupState(WZCL.GROUP_STATE.PROCESSING);
        return RVO.success(activityGroupService.getActivityGroupList(activityGroupDto));
    }
}